#include "include/login.h"
#include "include/logToFile.h"
#include <crypt.h>
#include <stdio.h>
#include <string.h>

//随机生成salt的函数
void generateSalt(char *salt,size_t len){

   static const char salt_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
    srand((unsigned int)time(NULL) ^ getpid());
    for (size_t i = 0; i < len - 1; ++i) {
        salt[i] = salt_chars[rand() % (sizeof(salt_chars) - 1)];
    }
    salt[len - 1] = '\0';
}
//生成密文
void generatePassword(const char *password,const char *salt,char *password_md5){
   
   //1.初始化结构体
   struct crypt_data data;
   memset(&data, 0, sizeof(data));

   //2.生成setting字符串
   char setting[32]={0};
   snprintf(setting,sizeof(setting),"$1$%s",salt);

   //3.生成密文
   char *p=crypt_r(password,setting, &data);
    if(p==NULL){
        //生成密文失败
        return ;
    }
    strncpy(password_md5, p, 1023);  // 假设调用方缓冲区大小为1024
    password_md5[1023] = '\0';  // 确保字符串终止
}


//服务器接收用户注册 
int userRegister(task_t *task,MYSQL*db,user_t *user){
    //1.接收用户名
    bzero(&task->_train,sizeof(task->_train));
    recv(task->_netfd,&task->_train,sizeof(task->_train),0);
    char username[1024]={0};
    strncpy(username,task->_train._data,task->_train._trainLen);
    username[task->_train._trainLen]='\0';
    //2.判断数据库中是否存在该用户
    char sql[1024]={0};
    snprintf(sql,sizeof(sql),"select * from users where username='%s'",username);
    const char *sql_user=sql;
    int count=selectUser(sql_user,db,user);
    if(count!=0){
        //数据库中存在该用户,给客户端发送空火车
        bzero(&task->_train,sizeof(task->_train));
        task->_train._trainLen=0;
        send(task->_netfd,&task->_train,sizeof(task->_train),0);
        return -1;
    }
    //2.1此时需要收明文给客户端发个标志 
    bzero(&task->_train,sizeof(task->_train));
    task->_train._trainLen=0;
    send(task->_netfd,&task->_train,sizeof(task->_train),0);
    //3.接收明文
    bzero(&task->_train,sizeof(task->_train));
    recv(task->_netfd,&task->_train,sizeof(task->_train),0);
    char password[1024]={0};
    strncpy(password,task->_train._data,task->_train._trainLen);
    password[task->_train._trainLen]='\0';
    //4.生成盐值,密文
    char salt[1024]={0};
    char password_md5[1024]={0};
    generateSalt(salt,16);
    generatePassword(password,salt,password_md5);
    //4.将用户名,密文,盐值插入数据库
    char sql_insert[1024]={0};
    snprintf(sql_insert,sizeof(sql_insert),"insert into users (username,encrypted_pass,salt,is_delete) values ('%s','%s','%s',0)",username,password_md5,salt);
    const char *sql_insert_user=sql_insert;
    execDb(sql_insert_user,db);
    return 0;
}

//用户登录
int userLogin(task_t *task,MYSQL*db,user_t *user){

    //1.接收用户名
    bzero(&task->_train,sizeof(task->_train));
    recv(task->_netfd,&task->_train,sizeof(task->_train),0);
    char username[1024]={0};
    strncpy(username,task->_train._data,task->_train._trainLen);
    username[task->_train._trainLen]='\0';
    printf("接收用户名:%s\n",username);
    LOG_INFO("接收用户名:%s",username);
    //2.判断数据库中是否存在该用户
    char sql[1024]={0};
    snprintf(sql,sizeof(sql),"select * from users where username='%s'",username);
    const char *sql_user=sql;   
    int count=selectUser(sql_user,db,user);
    if(count==0){
        //数据库中不存在该用户
        bzero(&task->_train,sizeof(task->_train));
        task->_train._trainLen=0;
        send(task->_netfd,&task->_train,sizeof(task->_train),0);
        return -1;
    }
    //3.若存在用户判断密文是否相同
    //3.1发送盐值给客户端
    bzero(&task->_train,sizeof(task->_train));
    task->_train._trainLen=strlen(user->user[0].salt);
    strcpy(task->_train._data,user->user[0].salt);
    send(task->_netfd,&task->_train,sizeof(task->_train),0);
    printf("发送盐值:%s\n",task->_train._data);
    LOG_INFO("发送盐值:%s",task->_train._data);
    //3.2接收密文
    bzero(&task->_train,sizeof(task->_train));
    recv(task->_netfd,&task->_train,sizeof(task->_train),0);
    char password_md5[1024]={0};
    strncpy(password_md5,task->_train._data,task->_train._trainLen);
    password_md5[task->_train._trainLen]='\0';
    printf("接收密文:%s\n",password_md5);
    LOG_INFO("接收密文:%s",password_md5);
    //3.3判断密文是否相同
    if(strcmp(password_md5,user->user[0].encrypted_pass)==0){
        //密文相同
        bzero(&task->_train,sizeof(task->_train));
        char ch[1024]={"登录成功"};
        task->_train._trainLen=strlen(ch);
        strcpy(task->_train._data,ch);
        send(task->_netfd,&task->_train,sizeof(task->_train),0);
        
        file_t file;
        //判断file表中有无此用户
        char sql_file[1024]={0};
        snprintf(sql_file,sizeof(sql_file),"select * from file where username='%s'",username);
        const char *sql_file_select=sql_file;
        int count_file=selectFile(sql_file_select,db,&file);
        if(count_file==0){
            //file表中无此用户 将username写入file表
        char sql[1024]={0};
        snprintf(sql,sizeof(sql),"insert into file (username,path) values('%s','%s')",username,"/");
        const char *sql_into=sql;
        execDb(sql_into,db);
        }
        return 0;
    }else{
        //密文不同
        bzero(&task->_train,sizeof(task->_train));
        char ch[1024]={"登录失败"};
        task->_train._trainLen=strlen(ch);
        strcpy(task->_train._data,ch);
        send(task->_netfd,&task->_train,sizeof(task->_train),0);
        return -1;
    }
}
//判断登录还是注册
int login_or_register(int netfd,accept_info_t *userinfo,task_t *task,MYSQL*db,user_t *user){
    char p = '0';
    recv(netfd,&p,sizeof(p),0);
    printf("p:%c\n",p);
    if(p == 'r'){
        printf("注册\n");
        //注册
        int ret = userRegister(task,db,user);
        if(ret == 0){
            printf("注册成功\n");
            strcpy(userinfo->username,user->user[0].username);
            return 0;
        }else{
            printf("注册失败\n");
            return -1;
        }
        
    }else if(p == 'l'){
        printf("登录\n");
        int ret = userLogin(task,db,user);
        if(ret == 0){
            printf("登录成功\n");
            strcpy(userinfo->username,user->user[0].username);
            return 0;
        }else{
            printf("登录失败\n");
            return -1;
        }
    }else{
        printf("输入错误\n");
        return -1;
    }
}

